# coding=utf-8
"""
作者：董新强 
创建时间：2020-8-11
描述：raw_quesion管理
"""
import re

import numpy
from sqlalchemy import func

from catsim import irt
from db_models.cat_abilities import CatAbilities
from db_models.cat_questions import CatQuestions
from db_models.orm_base import OrmBase
from db_models.raw_dim import RawDim
from db_models.raw_questions import RawQuestions
from framework.db_session import DbSession
from framework.msg import failure, ok
from framework.utilities import to_int, to_float, to_list, get_len, to_string
from services.admin.admin_base import AdminBase

question_pattern = re.compile('^\d+[．.、]')
options_pattern = re.compile('^[ABCD][．.、,，：:]?')


class RawQuestionManage(AdminBase):
    def __init__(self, usr):
        super().__init__(usr)

    @AdminBase.admin(failure(msg='获取待导入问题失败'))
    def get_list(self, dim):
        if not dim:
            return failure(msg='参数错误')
        ls = []
        with DbSession.create() as db:
            query = db.query(RawQuestions).filter(RawQuestions.dim == dim).order_by(RawQuestions.id)
            for v in query:
                ls.append(OrmBase.get_dict(v))

        return ok(data=ls)

    @AdminBase.admin(failure(msg='获取待导入问题失败'))
    def get_dim_list(self):
        ls = []
        with DbSession.create() as db:
            query = db.query(RawDim).order_by(RawDim.status).order_by(RawDim.dim)
            for v in query:
                ls.append(OrmBase.get_dict(v))

        return ok(data=ls)

    @AdminBase.admin(failure(msg='保存失败'))
    def update(self, reqs):
        qid = to_int(reqs.get('id '))
        if not qid:
            return failure(msg='参数错误')

        with DbSession.create() as db:
            question = db.query(RawQuestions).filter(RawQuestions.id == qid).first()
            if not question:
                return failure(msg='问题不存在')

            question.title = reqs['title']
            question.options = reqs['options']
            question.answer = reqs['answer']
            question.b = to_float(reqs['b'])
        return ok()

    @AdminBase.admin(failure(msg='导致正式题库失败'))
    def to_std(self, dim, aid):
        '''
        将raw_question的试题导入CatQuestions中
        :param dim: 维度
        :param aid: 能力ID
        :return:
        '''
        titles = set()
        with DbSession.create() as db:
            # 获取原先处在的题目数量
            ability = db.query(CatAbilities).filter(CatAbilities.id == aid).first()
            if not ability:
                return failure(msg='能力不存在')

            raw = db.query(RawDim).filter(RawDim.dim == dim).first()
            if not raw:
                return failure(msg='RawQuestion不存在')
            if raw.status:
                return failure(msg='已导入过')

            count = db.query(func.count(CatQuestions.id)).filter(CatQuestions.aid == aid).scalar() or 0

            query = db.query(RawQuestions.title, RawQuestions.options, RawQuestions.dim, RawQuestions.b, RawQuestions.answer) \
                .filter(RawQuestions.dim == dim) \
                .order_by(RawQuestions.dim).all()
            for title, options, dim, b, answer in query:
                if title in titles:  # 题干去重
                    continue
                titles.add(title)

                q = CatQuestions()

                q.a = 0.3  # 区分度
                q.b = b
                q.c, q.answer, q.type = RawQuestionManage.get_c(options, answer)
                q.d = 1  # 将近线

                info = irt.max_info_hpc(numpy.array([[q.a, q.b, q.c, q.d]]))
                q.info = float(info[0])
                q.aid = aid
                q.exp_rate = 0.5  # 曝光度

                q.title = title
                q.options = options

                db.add(q)

            # 更新能力题目数量字段
            ability.qnums = count + get_len(titles)
            raw.status = 1
        return ok(msg='导入成功')

    @staticmethod
    def get_c(options, answer):
        options_ls = to_list(options)
        opt_num = len(options_ls)

        answers = set(answer.lower())
        if len(answers) == 1:
            return 1.0 / opt_num, ''.join(list(answers)), 'MC%d' % (opt_num,)

        return 1.0 / (2 ** opt_num - 1), ''.join(list(answer)), 'MC%dM' % (opt_num,)

    @AdminBase.admin(failure(msg='删除失败'))
    def delete(self, qid):
        with DbSession.create() as db:
            db.query(RawQuestions).filter(RawQuestions.id == qid).delete()

    @AdminBase.admin(failure(msg='删除失败'))
    def create(self, reqs):
        dim = reqs.get('dim').strip()
        name = reqs.get('name').strip()
        ls = reqs.get('arr')
        if not isinstance(ls, list) or not dim or not name:
            return failure(msg='数据格式错误')

        with DbSession.create() as db:
            dim_instance = db.query(RawDim).filter(RawDim.dim == dim).first()
            if dim_instance:
                return failure(msg='维度已经存在')

            question_ls = []
            for v in ls:
                title = question_pattern.sub('', v['题干'].strip())
                a = options_pattern.sub('', v['A'].strip())
                b = options_pattern.sub('', v['B'].strip())
                c = options_pattern.sub('', v['C'].strip())
                d = options_pattern.sub('', v['D'].strip())
                anwer = v['答案'].strip()

                rq = RawQuestions()
                rq.title = title
                rq.options = to_string([{"id": "a", "name": a}, {"id": "b", "name": b}, {"id": "c", "name": c}, {"id": "d", "name": d}])
                rq.answer = anwer.lower()
                rq.dim = dim
                rq.b = to_float(v.get('b')) or 3.0
                question_ls.append(rq)

            dim_instance = RawDim()
            dim_instance.name = name
            dim_instance.dim = dim
            dim_instance.status = 0
            db.add(dim_instance)

            db.bulk_save_objects(question_ls)

        return ok(msg='导入成功')
